/**
 * mstdio.c
 *
 *  Created on: 2019-09-05
 *      Author: chenshisheng
 */

#include <mstdio.h>
#include <serial.h>
#include <stdarg.h>
#include <ctype.h>

#include "stream/chprintf.h"
#include "stream/mem_stream.h"
//#include "active.h"
#include "hw.h"
#include "shell.h"

#define SERIAL_FOR_STDIO 1
#define ITM_FOR_STDIO    0
//#define NULL_FOR_STDIO   1

#if SERIAL_FOR_STDIO
#include "stream/serial_stream.h"

#define STDIO_SERIAL Serial_0

static SerialStream_t _stdio;
static IoStream_t _noCachedstdio;
static struct _CombinationCode
{
    uint32_t tick;
    bool started;
}_combination;

static bool _Rx(Serial_t serial, uint8_t b)
{
    Stream_LineSignal_t sig;
    bool wanted = true;
    bool echo = true;

    if(b == 0x1b)
    {
        _combination.tick = HAL_GetTick();
        _combination.started = true;
        return false;
    }
    else if(_combination.started)
    {
        uint32_t tick = HAL_GetTick();

        if((tick - _combination.tick) < 10)
        {
            _combination.tick = tick;
            return false;
        }
        else
        {
            _combination.started = false;
        }
    }

    if((b == '\r') || (b == '\n'))
    {
        // 发送信号给shell
        sig.stream = & _stdio.stream;
        sig.tail = b;
        Shell_SendLineSignal(&sig);
    }
    else if(b == '\b')
    {
        if(Serial_IoCtl(serial, Serial_Ctl_DeleteLastRxBufferByte) != 1)
        {
            echo = false;
        }

        wanted = false; // 不将‘\b’字符存入buffer
    }
    else if(!isprint(b))
    {
        wanted = false;
    }

    if(echo)
    {
        Serial_SendByteWithoutBuffer(serial, b);
        if(b == '\b')
        {
            // XXX 用空格来清除之前的显示的字符
            Serial_SendByteWithoutBuffer(serial, ' ');
            Serial_SendByteWithoutBuffer(serial, '\b');
        }
    }

    return wanted;
}

static int _IoPut(void *instance, unsigned char b)
{
    IoStream_t *is = instance;
    Serial_t serial = (Serial_t)is->userData;

    Serial_SendByteWithoutBuffer(serial, b);
    return 1;
}

static int _IoGet(void *instance, unsigned char *pb)
{
    SerialStream_t *ss = instance;
    Serial_t serial = (Serial_t)ss->userData;

    return (Serial_RecvByteWithoutBuffer(serial, pb) == 0) ? 1 : 0;
}

void MStdio_Init(void)
{
    SerialStream_Init(&_stdio, STDIO_SERIAL);
    Serial_SetCallbacks(STDIO_SERIAL, NULL, NULL, _Rx);
    Serial_IoCtl(STDIO_SERIAL, Serial_Ctl_SetFlags, SERIAL_FLAG_AUTO_LINE);

    IoStream_InitWithoutBuffer(&_noCachedstdio, _IoPut, _IoGet, NULL, STDIO_SERIAL);

    nbdebug("\n----------\n%s\n", __func__);
}

#elif ITM_FOR_STDIO
#include "stream/itm_stream.h"

static ItmStream_t _stdio;
#define _stdioWithoutBuf _stdio

void MStdio_Init(void)
{
    ItmStream_Init(&_stdio, 0);
}

#else // NULL_FOR_STDIO
#include "stream/null_stream.h"

static NullStream_t _stdio;
#define _stdioWithoutBuf _stdio

void MStdio_Init(void)
{
    NullStream_Init(&_stdio);
}
#endif

Stream_t *MStdio_Stream(void)
{
    return (Stream_t *)&_stdio;
}

Stream_t *MStdio_NoCachedStream(void)
{
    return (Stream_t *)&_noCachedstdio;
}

/**
 *
 * @param fmt
 * @return
 * FIXME printf("\n")表现异常
 */
int printf(const char *fmt, ...)
{
    va_list args;
    int n;

    va_start(args, fmt);
    Stream_AcquireWrite(& _stdio);
    n = chvprintf(& _stdio, fmt, args);
    Stream_ReleaseWrite(& _stdio);
    va_end(args);

    return n;
}

int vprintf(const char *fmt, va_list vargs)
{
    int n;

    Stream_AcquireWrite(& _stdio);
    n = chvprintf(&_stdio, fmt, vargs);
    Stream_ReleaseWrite(& _stdio);

    return n;
}

int puts(const char *str)
{
    int n = 0;

    Stream_AcquireWrite(& _stdio);
    while(*str != '\0')
    {
        n += Stream_Put(& _stdio, *str++);
    }

//    n += Stream_Put(& _stdio, '\r');
    n += Stream_Put(& _stdio, '\n');

    Stream_ReleaseWrite(& _stdio);
    return n;
}

int putchar (int c)
{
    return Stream_Put(& _stdio, (unsigned char)c);
}

/**
 * 基于MsgQueue的printf,用于在中断处理函数内进行格式化输出
 * @param fmt
 * @return
 */
int mprintf(const char *fmt, ...)
{
    va_list args;
    int n;
    char buf[128];

    va_start(args, fmt);
    n = vsnprintf(buf, sizeof(buf), fmt, args);
    va_end(args);

    MsgQueue_Send(MsgQueue_Id_Debug, buf, n);
    return n;
}

void Mstdio_OnMPrintf(const MsgQueue_Msg_t *msg)
{
    Stream_Write(&_stdio, msg->data, msg->size);
}

/**
 * 基于轮循式发送的格式化输出，用于中断式发送所需的相关中断(可能)没有使能的场合
 * @param fmt
 * @return
 */
int nbprintf(const char *fmt, ...)
{
    va_list args;
    int n;

    va_start(args, fmt);
    Stream_AcquireWrite(& _noCachedstdio);
    n = chvprintf(& _noCachedstdio, fmt, args);
    Stream_ReleaseWrite(& _noCachedstdio);
    va_end(args);

    return n;
}
